﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using AndBurn.DDSReader;

namespace DnPakExplorer.Forms {

	public partial class DDSForm : Form {
		static Cursor mHandCursor;
		static Cursor mHandDragCusor;

		private Image mImage;
		private Rectangle mImageBounds;
		private MouseAction mMouseAction;
		private Selection mSelection;

		public DDSForm() {
			InitializeComponent();
		}

		static DDSForm() {
			ResourceManager rm = new ResourceManager(typeof(DnPakExplorer.Properties.Resources));
			mHandDragCusor = new Cursor(new MemoryStream((byte[])rm.GetObject("Cursor_Hand_Closed")));
			mHandCursor = new Cursor(new MemoryStream((byte[])rm.GetObject("Cursor_Hand_Opened")));
		}

		public void SetImage(Image image) {
			mImage = image;
			ContentSize = image.Size;
			mImageBounds.Size = image.Size;
			Padding f = this.Padding;
			mImageBounds.Location = new Point(0, 0);
			statusStrip1.Items[0].Text = mImageBounds.Width+"×"+mImageBounds.Height;
		}

		public void LoadDDS(Stream stream) {
			SetImage(DDS.LoadImage(stream));
		}

		private int ContentWidth {
			get { return ClientSize.Width; }
		}

		private int ContentHeight {
			get { return ClientSize.Height-statusStrip1.Height; }
		}

		private Size ContentSize {
			get { return new Size(ContentWidth, ContentHeight); }
			set { ClientSize = new Size(
				value.Width,
				value.Height+statusStrip1.Height); 
			}
		}


		Point mMouseLastDownPoint;
		private void OnMouseMove(object sender, MouseEventArgs e) {
			switch (mMouseAction) {
			case MouseAction.Draging:
				mImageBounds.X = mImageBounds.X + e.Location.X - mMouseLastDownPoint.X;
				mImageBounds.Y = mImageBounds.Y + e.Location.Y - mMouseLastDownPoint.Y;
				AjustImagePosition();
				Repaint();
				mMouseLastDownPoint = e.Location;
				break;
			case MouseAction.Selection:
				if (mSelection.started) {
					mSelection.pointEnd = new Point(e.Location.X-mImageBounds.X, e.Location.Y-mImageBounds.Y);
					DrawSelection();
					Rectangle rect = mSelection.SelectionRect();
					statusStrip1.Items[1].Text = rect.X +","+rect.Y +" "+rect.Width +","+rect.Height;
					
					
				} else {
					statusStrip1.Items[1].Text = (e.Location.X-mImageBounds.X)+","+(e.Y-mImageBounds.Y);
				}
				
				break;
			case MouseAction.Normal:
				if (mImageBounds.Width>ContentWidth || mImageBounds.Height>ContentHeight) 
					Cursor = mHandCursor;
				else
					Cursor = Cursors.Arrow;
				break;
			}
		}

		
		private void OnMouseDown(object sender, MouseEventArgs e) {
			if (mMouseAction == MouseAction.Normal && (mImageBounds.Width>ContentWidth || mImageBounds.Height>ContentHeight)) {
				mMouseAction = MouseAction.Draging;
				Capture = true;
				Cursor = mHandDragCusor;
			}
			if (mMouseAction == MouseAction.Selection) {
				mSelection.started = true;
				mSelection.compeleted = false;
				mSelection.pointStart = new Point(e.Location.X-mImageBounds.X, e.Location.Y-mImageBounds.Y);
			} else {
				mSelection = null;
			}

			mMouseLastDownPoint = e.Location;
		}

		private void OnMouseUp(object sender, MouseEventArgs e) {
			if (mMouseAction == MouseAction.Draging) {
				mMouseAction = MouseAction.Normal;
				Capture = false;
				Cursor = Cursors.Arrow;
			} else if (mMouseAction == MouseAction.Selection) {
				mSelection.started = false;
				mSelection.compeleted = true;
				mSelection.pointEnd = new Point(e.Location.X-mImageBounds.X, e.Location.Y-mImageBounds.Y);
			}
		}

		private void OnMouseLeave(object sender, EventArgs e) {
			Cursor = Cursors.Arrow;
		}

		private void AjustImagePosition() {
			mImageBounds.X = Math.Max(ContentWidth-mImageBounds.Width, mImageBounds.X);
			mImageBounds.Y = Math.Max(ContentHeight-mImageBounds.Height, mImageBounds.Y);
			mImageBounds.X = Math.Min(0, mImageBounds.X);
			mImageBounds.Y = Math.Min(0, mImageBounds.Y);
			if (mImageBounds.Width < ContentWidth)
				mImageBounds.X = (ContentWidth-mImageBounds.Width)/2;
			if (mImageBounds.Height < ContentHeight)
				mImageBounds.Y = (ContentHeight-mImageBounds.Height)/2;
		}

		private void OnPaint(object sender, PaintEventArgs e) {
			PaintBackground(e.Graphics);
			PaintImage(e.Graphics);
		}

		private void DubleBuffedPaint(Graphics ggg) {
			BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
			BufferedGraphics myBuffer = currentContext.Allocate(ggg, new Rectangle(0, 0, this.Width, this.Height));
			Graphics g = myBuffer.Graphics;
			Repaint(g);
			myBuffer.Render(ggg);
			myBuffer.Dispose();
			g.Dispose();
		}

		private void Repaint() {
			DubleBuffedPaint(this.CreateGraphics());
		}

		private void Repaint(Graphics g) {
			PaintBackground(g);
			PaintImage(g);
			mDrawnSelectionRect = false;
		}

		/// <summary>
		/// 创建一个画笔位图
		/// </summary>
		/// <param name="width">位图宽</param>
		/// <param name="height">位图高</param>
		/// <param name="Color">画笔代表的颜色</param>
		private static Bitmap CreateBrushImage(int width, int height, MenuIcon icon) {
			Bitmap burshBitmap = new Bitmap(width + 1, height + 1);
			Graphics g = Graphics.FromImage(burshBitmap);
			g.SmoothingMode = SmoothingMode.AntiAlias;
			switch (icon) {
			case MenuIcon.BackgroudLight:
				g.DrawRectangle(Pens.Gray, new Rectangle(0, 0, width + 1, height + 1));
				g.FillRectangle(new HatchBrush(HatchStyle.SolidDiamond, Color.WhiteSmoke, Color.LightGray),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudDark:
				g.FillRectangle(new HatchBrush(HatchStyle.SolidDiamond, Color.Black, ControlPaint.Light(Color.Black)),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudRed:
				g.FillRectangle(new HatchBrush(HatchStyle.SolidDiamond, Color.Red, Color.DarkRed),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudGreen:
				g.FillRectangle(new HatchBrush(HatchStyle.SolidDiamond, Color.Green, Color.DarkGreen),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudBlue:
				g.FillRectangle(new HatchBrush(HatchStyle.SolidDiamond, Color.Blue, Color.DarkBlue),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudSolidWhite:
				g.DrawRectangle(Pens.Gray, new Rectangle(0, 0, width + 1, height + 1));
				g.FillRectangle(new SolidBrush(Color.White),
					new Rectangle(0, 0, width, height));
				break;
			case MenuIcon.BackgroudSolidBlack:
				g.FillRectangle(new SolidBrush(Color.Black),
					new Rectangle(0, 0, width, height));
				break;
			}

			return burshBitmap;
		}

		enum MenuIcon{
			BackgroudDark,
			BackgroudLight,
			BackgroudGreen,
			BackgroudRed,
			BackgroudBlue,
			BackgroudSolidWhite,
			BackgroudSolidBlack,
		}


		Rectangle mLastSelectionRect;
		bool mDrawnSelectionRect;
		private void DrawSelection() {
			if (mDrawnSelectionRect) {
				Win32.DrawFocusRect(this.CreateGraphics().GetHdc(), ref mLastSelectionRect);
				mDrawnSelectionRect = false;
			}
			if (mSelection != null) {
				if (mSelection.started || mSelection.compeleted) {
					Rectangle rect = mSelection.SelectionRect();
					rect.X += mImageBounds.X;
					rect.Y += mImageBounds.Y;
					rect.Width = rect.Right;
					rect.Height = rect.Bottom;
					Win32.DrawFocusRect(this.CreateGraphics().GetHdc(), ref rect);
					//Rect.Location = PointToScreen(Rect.Location);
					//ControlPaint.DrawReversibleFrame(Rect, Color.White, FrameStyle.Dashed);
					mLastSelectionRect = rect;
					mDrawnSelectionRect = true;
				}
			}
		}

		private void PaintImage(Graphics g) {
			if (mImage != null) {
				Rectangle srcRect = new Rectangle();
				srcRect.X = Math.Min(0, -mImageBounds.X);
				srcRect.Y = Math.Min(0, -mImageBounds.Y);
				srcRect.Width = Util.Clamp(mImageBounds.Width-(mImageBounds.Right-ContentWidth), 0, mImageBounds.Width);
				srcRect.Height = Util.Clamp(mImageBounds.Height-(mImageBounds.Bottom-ContentHeight), 0, mImageBounds.Height);
				g.DrawImageUnscaledAndClipped(mImage, mImageBounds);
			}
		}

		static Brush mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.WhiteSmoke, Color.LightGray);
		private void PaintBackground(Graphics g) {
			g.FillRectangle(mBackgroudBrush, new Rectangle(0, 0, ContentWidth, ContentHeight));
		}

		private void OnSizeChanged(object sender, EventArgs e) {
			if (this.DesktopBounds.Width > Screen.PrimaryScreen.WorkingArea.Width 
				|| this.DesktopBounds.Height>Screen.PrimaryScreen.WorkingArea.Height) {
					this.DesktopBounds = new Rectangle(
					this.DesktopBounds.Width > Screen.PrimaryScreen.WorkingArea.Width?0:Bounds.X,
					this.DesktopBounds.Height>Screen.PrimaryScreen.WorkingArea.Height?0:Bounds.Y, 
					Math.Min(Bounds.Width, Screen.PrimaryScreen.WorkingArea.Width), 
					Math.Min(Bounds.Height, Screen.PrimaryScreen.WorkingArea.Height));
			}
			AjustImagePosition();
			Repaint();
		}

		enum MouseAction {
			Normal,
			Draging,
			Selection,
		}

		private void DDSForm_KeyDown(object sender, KeyEventArgs e) {
			if (mMouseAction == MouseAction.Normal && e.KeyCode == Keys.ShiftKey) {
				mMouseAction = MouseAction.Selection;
				mSelection = new Selection();
				Cursor = Cursors.Arrow;
			}
		}

		private void DDSForm_KeyPress(object sender, KeyPressEventArgs e) {

		}

		private void DDSForm_KeyUp(object sender, KeyEventArgs e) {
			if (mMouseAction == MouseAction.Selection && e.KeyCode == Keys.ShiftKey) {
				mMouseAction = MouseAction.Normal;
				statusStrip1.Items[1].Text = "";
				Cursor = Cursors.Arrow;
			}
		}

		class Selection {
			public bool started;
			public bool compeleted;
			public Point pointStart;
			public Point pointEnd;

			public Rectangle SelectionRect() {
				return new Rectangle(
					Math.Min(pointStart.X, pointEnd.X),
					Math.Min(pointStart.Y, pointEnd.Y),
					Math.Abs(pointEnd.X-pointStart.X),
					Math.Abs(pointEnd.Y-pointStart.Y)
				);
			}
		}

		private void DDSForm_MouseClick(object sender, MouseEventArgs e) {
			if (e.Button == System.Windows.Forms.MouseButtons.Right) {
				ContextMenuStrip menu = new ContextMenuStrip();
				menu.Items.Add("浅色背景", CreateBrushImage(22, 22, MenuIcon.BackgroudLight), OnContextMenu);
				menu.Items.Add("深色背景", CreateBrushImage(22, 22, MenuIcon.BackgroudDark), OnContextMenu);
				menu.Items.Add("绿色背景", CreateBrushImage(22, 22, MenuIcon.BackgroudGreen), OnContextMenu);
				menu.Items.Add("红色背景", CreateBrushImage(22, 22, MenuIcon.BackgroudRed), OnContextMenu);
				menu.Items.Add("蓝色背景", CreateBrushImage(22, 22, MenuIcon.BackgroudBlue), OnContextMenu);
				menu.Items.Add("纯白背景", CreateBrushImage(22, 22, MenuIcon.BackgroudSolidWhite), OnContextMenu);
				menu.Items.Add("纯黑背景", CreateBrushImage(22, 22, MenuIcon.BackgroudSolidBlack), OnContextMenu);
				menu.Items.Add(new ToolStripSeparator());
				menu.Items.Add("实际大小", null, OnContextMenu);
				menu.Items.Add("适合窗口", null, OnContextMenu);
				menu.Items.Add("缩放", null, OnContextMenu);
				menu.Show(Cursor.Position);
			}
		}

		private void OnContextMenu(object sender, EventArgs e) {
			ToolStripItem item = sender as ToolStripItem;
			if (item.Text == "浅色背景") {
				mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.WhiteSmoke, Color.LightGray);
			} else if (item.Text == "深色背景") {
				mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.Black, ControlPaint.Light(Color.Black));
			} else if (item.Text == "绿色背景") {
				mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.Green, Color.DarkGreen);
			} else if (item.Text == "红色背景") {
				mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.Red, Color.DarkRed);
			} else if (item.Text == "蓝色背景") {
				mBackgroudBrush = new HatchBrush(HatchStyle.SolidDiamond, Color.Blue, Color.DarkBlue);
			} else if (item.Text == "纯白背景") {
				mBackgroudBrush = new SolidBrush(Color.White);
			} else if (item.Text == "纯黑背景") {
				mBackgroudBrush = new SolidBrush(Color.Black);
			}
			Repaint();
		}
	}
}
